﻿using System;
using System.Collections.Generic;
using Co9320.NamaAlert.Model.TagServer;

namespace Co9320.NamaAlert.CommunicationControl
{
	internal partial class OneWayTransactor
	{
		private const int AddModifyMaxCount = 3;
		private const int DeleteMaxCount = 1;
		private const int ListDefaultCapacity = 5;

		private enum RequestKind
		{
			Add=1,
			Delete=2
		}

		private class Lists
		{
			public List<string> Add;
			public List<string> Delete;

			public Lists()
			{
				Add = new List<string>(ListDefaultCapacity);
				Delete = new List<string>(ListDefaultCapacity);
			}
		}

		Dictionary<LiveInfo,Lists> Dict;
		private object SyncRoot;

		public OneWayTransactor()
		{
			Dict = new Dictionary<LiveInfo, Lists>();
			SyncRoot = new object();
		}

		public void Add(string StationId, string Caster, IList<Model.TagModel> Tags)
		{
			Regist(StationId, Caster, RequestKind.Add, Tags);
		}

		public void Delete(string StationId, string Caster, IList<Model.TagModel> Tags)
		{
			Regist(StationId, Caster, RequestKind.Delete, Tags);
		}

		private void Regist(string StationId, string Caster,RequestKind  Kind, IList<Model.TagModel> Tags)
		{
			if (StationId == null || Caster == null ||
				Tags == null || Tags.Count == 0)
			{
				return;
			}

			lock (SyncRoot)
			{
				LiveInfo info = new LiveInfo(StationId, Caster);

				if (!Dict.ContainsKey(info))
				{
					Dict.Add(info, new Lists());
				}

				var lst = Dict[info];

				foreach (Model.TagModel tag in Tags)
				{
                    if (tag == null || tag.Value.Trim().Length == 0 || tag.Kind != Co9320.NamaAlert.Model.TagKind.User)
					{
						continue;
					}
					else
					{
						switch (Kind)
						{
							case RequestKind.Add:
								lst.Add.Add(tag.Value);
								break;

							case RequestKind.Delete:
								lst.Delete.Add(tag.Value);
								break;

							default:
								continue;
						}
					}
				}
			}
		}

		public ParametersCollection GetParameters()
		{
			ParametersCollection Ret = new ParametersCollection();

			lock (SyncRoot)
			{
				foreach (var Pair in Dict)
				{
					EachProcess(Pair.Key, Pair.Value, Ret);
				}
			}

			Dict.Clear();

			return Ret;
		}

		private void EachProcess(LiveInfo liveInfo, Lists lists, ParametersCollection Ret)
		{
			if (lists.Add.Count == 0 && lists.Delete.Count == 0)
			{
				return;
			}

			AddDeleteParamerter AddParam = null;
			AddDeleteParamerter DelParam = null;
			ModifyParameter ModParam = null;

			if (lists.Add.Count == 0 && lists.Delete.Count != 0)
			{
				DelParam = new AddDeleteParamerter();
				DelParam.StationId = liveInfo.StationId;
				DelParam.Caster = liveInfo.Caster;
				DelParam.TagValue = new string[] { lists.Delete[0] };
			}
			else if (lists.Add.Count != 0 && lists.Delete.Count == 0)
			{
				AddParam = new AddDeleteParamerter();
				AddParam.StationId = liveInfo.StationId;
				AddParam.Caster = liveInfo.Caster;

				//AddParam.TagValue = new ArrayOfString();
				List<string> lst = new List<string>();

				for (int i = 0; i < lists.Add.Count; i++)
				{
					if (i >= AddModifyMaxCount)
					{
						break;
					}

					lst.Add(lists.Add[i]);
				}

				AddParam.TagValue = lst.ToArray();
			}
			else
			{
				int Diff = lists.Delete.Count - lists.Add.Count;
				ModParam = new ModifyParameter();
				ModParam.StationId = liveInfo.StationId;
				ModParam.Caster = liveInfo.Caster;
				List<ModifyPair> Tags = new List<ModifyPair>();

				ModifyPair Pair=null;

				if (Diff == 0)
				{
					for (int i = 0; i < lists.Add.Count; i++)
					{
						if (i >= AddModifyMaxCount)
						{
							break;
						}

						Pair = new ModifyPair();
						Pair.ModifyFrom = lists.Delete[i];
						Pair.ModifyTo = lists.Add[i];
						Tags.Add(Pair);
					}

					ModParam.Tags = Tags.ToArray();
				}
				else if (Diff > 0)
				{
					for (int i = 0; i < lists.Add.Count; i++)
					{
						if (i >= AddModifyMaxCount)
						{
							break;
						}

						Pair = new ModifyPair();
						Pair.ModifyFrom = lists.Delete[i];
						Pair.ModifyTo = lists.Add[i];
						Tags.Add(Pair);
					}

					ModParam.Tags = Tags.ToArray();

					int DelIdx = lists.Add.Count > AddModifyMaxCount ? AddModifyMaxCount : lists.Add.Count;
					//DelIdx++;

					DelParam = new AddDeleteParamerter();
					DelParam.StationId = liveInfo.StationId;
					DelParam.Caster = liveInfo.Caster;
					DelParam.TagValue = new string[] { lists.Delete[DelIdx] };
				}
				else
				{
					for (int i = 0; i < lists.Delete.Count; i++)
					{
						if (i >= AddModifyMaxCount)
						{
							break;
						}

						Pair = new ModifyPair();
						Pair.ModifyFrom = lists.Delete[i];
						Pair.ModifyTo = lists.Add[i];
						Tags.Add(Pair);
					}

					ModParam.Tags = Tags.ToArray();

					int AddIdx = lists.Delete.Count > AddModifyMaxCount ? AddModifyMaxCount : lists.Delete.Count;
					//AddIdx++;

					int Limit = AddIdx + AddModifyMaxCount;
					AddParam = new AddDeleteParamerter();
					AddParam.StationId = liveInfo.StationId;
					AddParam.Caster = liveInfo.Caster;
					List<string> lst = new List<string>();

					for (int i = AddIdx; i < lists.Add.Count; i++)
					{
						if (i >= Limit)
						{
							break;
						}

						lst.Add(lists.Add[i]);
					}

					AddParam.TagValue = lst.ToArray();
				}
			}

			if (DelParam != null)
			{
				Ret.RegistDeleteParameter(DelParam);
			}
			if (AddParam != null)
			{
				Ret.RegistAddParameter(AddParam);
			}
			if (ModParam != null)
			{
				Ret.RegistModifyParameter(ModParam);
			}
		}

	}
}
